﻿using ALEXBlog.Entity;
using ALEXBlog.IRepository.Redis;
using ALEXBlog.IService.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ALEXBlog.Service.Redis
{
    public class RedisService : IRedisService
    {
        IRedisRepository redisContext;
        public RedisService(IRedisRepository redisRepository)
        {
            redisContext = redisRepository;
        }

        /// <summary>
        /// 将实体解析为键值对
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="entity"></param>
        /// <returns></returns>
        public virtual Dictionary<string, object> SerializeToRedisKeyValues<TEntity>(TEntity entity) where TEntity : BaseModel
        {
            var dic = new Dictionary<string, object>();
            var keyPrecursor = $"{nameof(TEntity)}:{entity.Id}:";
            foreach (var item in entity.GetType().GetProperties())
            {
                dic.Add(keyPrecursor + item.Name, item.GetValue(entity));
            }
            return dic;
        }

        /// <summary>
        /// 获取规范化的redisKey
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="id"></param>
        /// <returns></returns>
        public virtual string GetSerializeKey<TEntity>(string id) => $"{nameof(TEntity)}:{id}";


        /// <summary>
        /// 键是否存在
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual async Task<bool> ExistAsync<TEntity>(string id) where TEntity : BaseModel
        {
            return await redisContext.ExistAsync(GetSerializeKey<TEntity>(id) + ":*");
        }

        /// <summary>
        /// 设置键值对
        /// </summary>
        /// <param name="key"></param>
        /// <param name="Value"></param>
        /// <param name="cacheTime"></param>
        /// <returns></returns>
        public virtual async Task<bool> SetAsync<TEntity>(TEntity Entity, TimeSpan cacheTime) where TEntity : BaseModel
        {
            var dic = SerializeToRedisKeyValues(Entity);
            bool isCompleta = true;
            foreach (var item in dic)
            {
                isCompleta = await redisContext.SetAsync(item.Key, item.Value.ToString(), cacheTime);
            }
            return isCompleta;
        }

        /// <summary>
        /// 设置键值对
        /// </summary>
        /// <param name="key"></param>
        /// <param name="Value"></param>
        /// <param name="cacheTime"></param>
        /// <returns></returns>
        public virtual async Task<bool> SetAsync<TEntity>(TEntity Entity) where TEntity : BaseModel
        {
            var dic = SerializeToRedisKeyValues(Entity);
            bool isCompleta = true;
            foreach (var item in dic)
            {
                isCompleta = await redisContext.SetAsync(item.Key, item.Value.ToString());
            }
            return isCompleta;
        }


        /// <summary>
        /// 删除键值对
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual async Task<long> RemoveAsync<TEntity>(string id) where TEntity : BaseModel
        {
            var keys = redisContext.GetServer().Keys(redisContext.GetDatabase().Database, GetSerializeKey<TEntity>(id) + ":*")
                .Select(item => item.ToString())
                .ToArray();
            return await redisContext.RemoveAsync(keys);
        }

        /// <summary>
        /// 根据id获取实体
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual async Task<TEntity> GetAsync<TEntity>(string id)
        {
            var keys = redisContext.GetServer().Keys(redisContext.GetDatabase().Database, GetSerializeKey<TEntity>(id) + ":*");
            var entittyNames = keys.Select(key => key.ToString().Substring(0, key.ToString().LastIndexOf(":")));
            var obj = Activator.CreateInstance(typeof(TEntity));
            foreach (var key in keys)
            {
                typeof(TEntity).GetProperty(key).SetValue(obj, await redisContext.GetAsync(key));
            }
            return (TEntity)obj;

        }


        /// <summary>
        /// 根据id与字段名获取字段的缓存值
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual async Task<string> GetAsync<TEntity>(string id, string entityName)
        {
            var key = GetSerializeKey<TEntity>(id) + $":{entityName}";
            return await redisContext.GetAsync(key);
        }

        public Task ClearAsync()
        {
           return redisContext.ClearAsync();
        }

        public Task ListClearAsync(string key)
        {
            return redisContext.ListClearAsync(key);
        }

        public Task<long> ListFirstPushAsync<TEntity>(string redisKey, params TEntity[] redisValue) where TEntity : BaseModel
        {
            return redisContext.ListFirstPushAsync(redisKey, redisValue);
        }

        public Task<string> ListFirstRemoveAsync(string key)
        {
            return redisContext.ListFirstRemoveAsync(key);
        }

        public Task<TEntity> ListFirstRemoveAsync<TEntity>(string key) where TEntity : BaseModel
        {
            return redisContext.ListFirstRemoveAsync<TEntity>(key);
        }

        public Task<IEnumerable<TEntity>> ListGetAsync<TEntity>(string key) where TEntity : BaseModel
        {
            return redisContext.ListGetAsync<TEntity>(key);
        }

        public Task<long> ListLastPushAsync<TEntity>(string redisKey, params TEntity[] redisValue) where TEntity : BaseModel
        {
            return redisContext.ListLastPushAsync(redisKey, redisValue);
        }

        public Task<string> ListLastRemoveAsync(string key)
        {
            return redisContext.ListLastRemoveAsync(key);
        }

        public Task<TEntity> ListLastRemoveAsync<TEntity>(string key) where TEntity : BaseModel
        {
            return redisContext.ListLastRemoveAsync<TEntity>(key);
        }

        public Task<long> ListLengthAsync(string key)
        {
            return redisContext.ListLengthAsync(key);
        }

        public Task<IEnumerable<string>> ListRangeGetAsync(string key)
        {
            return redisContext.ListRangeGetAsync(key);
        }

        public Task<IEnumerable<string>> ListRangeGetAsync(string key, int startIndex, int stopIndex)
        {
            return redisContext.ListRangeGetAsync(key, startIndex, stopIndex);
        }

        public Task<IEnumerable<TEntity>> ListRangeGetAsync<TEntity>(string key, int startIndex, int stopIndex) where TEntity : BaseModel
        {
            return redisContext.ListRangeGetAsync<TEntity>(key, startIndex, stopIndex);
        }

        public Task<long> ListRangeRemoveAsync(string key, string value, long type = 0)
        {
            return redisContext.ListRangeRemoveAsync(key, value, type);
        }

        
    }
}
